#####################################################################
# -*- coding: iso-8859-1 -*-                                        #
#                                                                   #
# Frets on Fire                                                     #
# Copyright (C) 2006 Sami Kyostila                                  #
#                                                                   #
# This program is free software; you can redistribute it and/or     #
# modify it under the terms of the GNU General Public License       #
# as published by the Free Software Foundation; either version 2    #
# of the License, or (at your option) any later version.            #
#                                                                   #
# This program is distributed in the hope that it will be useful,   #
# but WITHOUT ANY WARRANTY; without even the implied warranty of    #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     #
# GNU General Public License for more details.                      #
#                                                                   #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software       #
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,        #
# MA  02110-1301, USA.                                              #
#####################################################################

import Player
from Song import Note, Tempo
from Mesh import Mesh
import Theme
import Config
import Log
import pygame

from OpenGL.GL import *
import math

#KEYS = [Player.KEY1, Player.KEY2, Player.KEY3, Player.KEY4, Player.KEY5]
PLAYER1KEYS    = [Player.KEY1, Player.KEY2, Player.KEY3, Player.KEY4, Player.KEY5]
PLAYER1ACTIONS = [Player.ACTION1, Player.ACTION2]
PLAYER2KEYS    = [Player.PLAYER_2_KEY1, Player.PLAYER_2_KEY2, Player.PLAYER_2_KEY3, Player.PLAYER_2_KEY4, Player.PLAYER_2_KEY5]
PLAYER2ACTIONS = [Player.PLAYER_2_ACTION1, Player.PLAYER_2_ACTION2]


class Guitar:
  def __init__(self, engine, editorMode = False, player = 0):
    self.engine         = engine
    self.boardWidth     = 4.0
    self.boardLength    = 12.0
    self.beatsPerBoard  = 5.0
    self.strings        = 5
    self.fretWeight     = [0.0] * self.strings
    self.fretActivity   = [0.0] * self.strings
    self.fretColors     = [(0, 1, 0), (1, 0, 0), (1, 1, 0), (0, 0, 1), (1, 0, 1), (.6, .6, .6), (0, 0, 1)]
    self.playedNotes    = []
    self.editorMode     = editorMode
    self.selectedString = 0
    self.time           = 0.0
    self.pickStartPos   = 0
    self.leftyMode      = False
    self.twoChord       = 0
    self.hopoActive     = 0
    self.hopoLast       = -1
    self.hopoColor      = (1, 1, 1)
    self.hopoColor2      = (1, 1, 1)
    self.player         = player
    
    self.jurgenTimer      = pygame.time.Clock()
    self.jurgenStarted  = False
    self.rockMeter      = 0
    self.jurgenTimeLeft = 0.0
    self.jurgenPower    = 0.0
    self.startPosition    = 0
    self.jurgenMultiplier = 1
    self.jPowerNotes    = Config.get("failing", "changenotecolor_jurgen")
    self.failed         = False
    
    self.currentBpm     = 50.0
    self.targetBpm      = self.currentBpm
    self.fakeCurrentBpm = self.currentBpm
    self.fakeBpm        = self.currentBpm
    self.marginLimit = 110

    self.Za = 0.0
    self.Z2a = 0.0
    self.zB = 0.0
    self.zBa = 0.0
    self.zBArray = []
    self.hyperS = False

    self.ScoreMultiplier = 1

    self.fireColor = [ [(.75, .38, .027),(.75, .38, .027),(.75, .38, .027),
                        (.75, .38, .027)],
                       [(.75, .38, .027),(.75, .38, .027),(.75, .38, .027),
                        (.75, .38, .027)],
                       [(.75, .38, .027),(.75, .38, .027),(.75, .38, .027),
                        (.75, .38, .027)],
                       [(.75, .38, .027),(.75, .38, .027),(.75, .38, .027),
                        (.75, .38, .027)],
                       [(.75, .38, .027),(.75, .38, .027),(.75, .38, .027),
                        (.75, .38, .027)],
                       [(.75, .38, .027),(.75, .38, .027),(.75, .38, .027),
                        (.75, .38, .027)] ]
    fire_color = [[0 for i in range(4)] for j in range(5)]
    fire_color[0][0]  = Config.get("theme", "hitflame1_color1X")
    fire_color[1][0]  = Config.get("theme", "hitflame2_color1X")
    fire_color[2][0]  = Config.get("theme", "hitflame3_color1X")
    fire_color[3][0]  = Config.get("theme", "hitflame4_color1X")
    fire_color[4][0]  = Config.get("theme", "hitflame5_color1X")
    fire_color[0][1]  = Config.get("theme", "hitflame1_color2X")
    fire_color[1][1]  = Config.get("theme", "hitflame2_color2X")
    fire_color[2][1]  = Config.get("theme", "hitflame3_color2X")
    fire_color[3][1]  = Config.get("theme", "hitflame4_color2X")
    fire_color[4][1]  = Config.get("theme", "hitflame5_color2X")
    fire_color[0][2]  = Config.get("theme", "hitflame1_color3X")
    fire_color[1][2]  = Config.get("theme", "hitflame2_color3X")
    fire_color[2][2]  = Config.get("theme", "hitflame3_color3X")
    fire_color[3][2]  = Config.get("theme", "hitflame4_color3X")
    fire_color[4][2]  = Config.get("theme", "hitflame5_color3X")
    fire_color[0][3]  = Config.get("theme", "hitflame1_color4X")
    fire_color[1][3]  = Config.get("theme", "hitflame2_color4X")
    fire_color[2][3]  = Config.get("theme", "hitflame3_color4X")
    fire_color[3][3]  = Config.get("theme", "hitflame4_color4X")
    fire_color[4][3]  = Config.get("theme", "hitflame5_color4X")
    i = 0
    while i <= 4:
      j = 0
      while j <= 3:
        if fire_color[i][j] != "None":
          self.fireColor[i][j] = Theme.hexToColor(fire_color[i][j])
        j += 1
      i += 1

    self.fireSize  = [ [(.075, .075),(.075, .075),(.075, .075),
                        (.075, .075)],
                       [(.075, .075),(.075, .075),(.075, .075),
                        (.075, .075)],
                       [(.075, .075),(.075, .075),(.075, .075),
                        (.075, .075)],
                       [(.075, .075),(.075, .075),(.075, .075),
                        (.075, .075)],
                       [(.075, .075),(.075, .075),(.075, .075),
                        (.075, .075)],
                       [(.075, .075),(.075, .075),(.075, .075),
                        (.075, .075)] ]
    fire_size = [[0 for i in range(4)] for j in range(5)]
    fire_size[0][0]  = Config.get("theme", "hitflame1_size1X")
    fire_size[1][0]  = Config.get("theme", "hitflame2_size1X")
    fire_size[2][0]  = Config.get("theme", "hitflame3_size1X")
    fire_size[3][0]  = Config.get("theme", "hitflame4_size1X")
    fire_size[4][0]  = Config.get("theme", "hitflame5_size1X")
    fire_size[0][1]  = Config.get("theme", "hitflame1_size2X")
    fire_size[1][1]  = Config.get("theme", "hitflame2_size2X")
    fire_size[2][1]  = Config.get("theme", "hitflame3_size2X")
    fire_size[3][1]  = Config.get("theme", "hitflame4_size2X")
    fire_size[4][1]  = Config.get("theme", "hitflame5_size2X")
    fire_size[0][2]  = Config.get("theme", "hitflame1_size3X")
    fire_size[1][2]  = Config.get("theme", "hitflame2_size3X")
    fire_size[2][2]  = Config.get("theme", "hitflame3_size3X")
    fire_size[3][2]  = Config.get("theme", "hitflame4_size3X")
    fire_size[4][2]  = Config.get("theme", "hitflame5_size3X")
    fire_size[0][3]  = Config.get("theme", "hitflame1_size4X")
    fire_size[1][3]  = Config.get("theme", "hitflame2_size4X")
    fire_size[2][3]  = Config.get("theme", "hitflame3_size4X")
    fire_size[3][3]  = Config.get("theme", "hitflame4_size4X")
    fire_size[4][3]  = Config.get("theme", "hitflame5_size4X")
    i = 0
    while i <= 4:
      j = 0
      while j <= 3:
        if fire_size[i][j] != "None":
          self.fireSize[i][j] = (eval(fire_size[i][j]), eval(fire_size[i][j]))
        j += 1
      i += 1
      

    if player == 0:
      self.keys = PLAYER1KEYS
      self.actions = PLAYER1ACTIONS
      #self.ACTION1 = Player.ACTION1
      #self.ACTION2 = Player.ACTION2
    else:
      self.keys = PLAYER2KEYS
      self.actions = PLAYER2ACTIONS
      #self.ACTION1 = Player.PLAYER_2_ACTION1
      #self.ACTION2 = Player.PLAYER_2_ACTION2    
    
    self.setBPM(self.currentBpm)

    engine.resource.load(self,  "noteMesh", lambda: Mesh(engine.resource.fileName("note.dae")))
    engine.resource.load(self,  "jurgenNoteMesh", lambda: Mesh(engine.resource.fileName("jurgennote.dae")))
    engine.resource.load(self,  "keyMesh",  lambda: Mesh(engine.resource.fileName("key.dae")))
    engine.loadSvgDrawing(self, "glowDrawing", "glow.svg",  textureSize = (128, 128))
    engine.loadSvgDrawing(self, "neckDrawing", "neck.svg",  textureSize = (256, 256))
    engine.loadSvgDrawing(self, "hitflames1Drawing", "hitflames1.svg",  textureSize = (128, 128))
    engine.loadSvgDrawing(self, "hitflames2Drawing", "hitflames2.svg",  textureSize = (128, 128))
    engine.loadSvgDrawing(self, "hitglowDrawing", "hitglow.svg",  textureSize = (128, 128))
    engine.loadSvgDrawing(self, "hitglow2Drawing", "hitglow2.svg",  textureSize = (128, 128))

    fret0_color  = Config.get("theme", "fret0_color")    
    fret1_color  = Config.get("theme", "fret1_color")
    fret2_color  = Config.get("theme", "fret2_color")
    fret3_color  = Config.get("theme", "fret3_color")
    fret4_color  = Config.get("theme", "fret4_color")
    fret5_color  = Config.get("theme", "fret5_color")
    jurgenpower_color = Config.get("theme", "jurgenpower_color")

    hopo_color  = Config.get("theme", "hopo_color")
    hopo_color2  = Config.get("theme", "hopo_color2")
    
    if fret0_color != "None":
      self.fretColors[0] = Theme.hexToColor(fret0_color)
    if fret1_color != "None":
      self.fretColors[1] = Theme.hexToColor(fret1_color)      
    if fret2_color != "None":
      self.fretColors[2] = Theme.hexToColor(fret2_color)
    if fret3_color != "None":
      self.fretColors[3] = Theme.hexToColor(fret3_color)
    if fret4_color != "None":
      self.fretColors[4] = Theme.hexToColor(fret4_color)
    if fret5_color != "None":
      self.fretColors[5] = Theme.hexToColor(fret5_color)
    if jurgenpower_color != "None":
      self.fretColors[6] = Theme.hexToColor(jurgenpower_color)

    if hopo_color != "None":
      self.hopoColor = Theme.hexToColor(hopo_color)

    if hopo_color2 != "None":
      self.hopoColor2 = Theme.hexToColor(hopo_color2)

    key_color  = Config.get("theme", "key_color")

    if key_color != "None":
      self.keyColor = Theme.hexToColor(key_color)

    key2_color  = Config.get("theme", "key2_color")

    if key2_color != "None":
      self.key2Color = Theme.hexToColor(key2_color)
      
    self.twoChordMax = Config.get("player%d" %(player), "two_chord_max")
    self.disableNoteSFX  = Config.get("video", "disable_notesfx")
    self.disableFretSFX  = Config.get("video", "disable_fretsfx")
    
    self.boardSpeed  = Config.get("game", "board_speed")

    self.disableFlame1SFX = Config.get("video", "disable_flame1sfx")
    self.disableFlame2SFX = Config.get("video", "disable_flame2sfx")

    self.TracksType = Config.get("game", "tracks_type")
    self.TracksColor = Config.get("theme", "tracks_color")
    self.BarsColor = Config.get("theme", "bars_color")

    if str(self.TracksColor) != "off":
      self.TracksColor = Theme.hexToColor(self.TracksColor)
    if str(self.BarsColor) != "off":
      self.BarsColor = Theme.hexToColor(self.BarsColor)

    self.tailWidth      = .075    ## Width of the tails
    self.tailHeight     = 0.1     ## Height of the tails
    self.tailRoundness  = 2       ## Roundness of the tails, higher number for smoother curves (consumes more cpu too)
    self.tail2Size      = 0.25    ## Size for the second part of the tail (the end/tip),
                                  ## if the second part of the tail increases in size, the first part will be shorter

    tailWidth       = Config.get("theme", "tail_width")
    tailHeight      = Config.get("theme", "tail_height")
    tailRoundness   = Config.get("theme", "tail_roundness")
    tail2Size       = Config.get("theme", "tail_size2")
    
    if tailWidth != "None":
      self.tailWidth = float(tailWidth)
    if tailHeight != "None":
      self.tailHeight = float(tailHeight)
    if tailRoundness != "None":
      self.tailRoundness = int(tailRoundness)
    if tail2Size != "None":
      self.tail2Size = float(tail2Size)

    self.initTails()  ## Initialize the vectors for the tail
  
    
  def selectPreviousString(self):
    self.selectedString = (self.selectedString - 1) % self.strings

  def selectString(self, string):
    self.selectedString = string % self.strings

  def selectNextString(self):
    self.selectedString = (self.selectedString + 1) % self.strings

  def setBPM(self, bpm, hyper = False):
    self.setMargin()
    self.fakeBpm           = bpm
    self.fakePeriod        = 60000.0 / bpm
    self.fakeCurrentBpm    = bpm
    self.hyperS            = hyper

  def setMargin(self):
    margin = self.currentBpm
    if margin > self.marginLimit:
      margin = self.marginLimit
    self.earlyMargin       = 60000.0 / margin / 3.5
    self.lateMargin        = 60000.0 / margin / 3.5
    self.noteReleaseMargin = 60000.0 / margin / 2

  def setMultiplier(self, multiplier):
    self.ScoreMultiplier = multiplier
    

  def getDifficulty(self):
    difficulty = Config.get("player%d" %(self.player), "difficulty")
    return difficulty


  def initTails(self):
    width = self.tailWidth            
    height = self.tailHeight  
    v1 = [0 for i in range(4)]
    v2 = [0 for i in range(4)]

    ##Init. vectors for the first part of the tail
    v1[0] = self.CREATE_VECTOR(-width, 0, 0)
    v1[1] = self.CREATE_VECTOR(-width, height, 0)
    v1[2] = self.CREATE_VECTOR(width, height, 0)
    v1[3] = self.CREATE_VECTOR(width, 0, 0)

    self.SMixBezier1(v1, 3)

    ##Init. vectors for the second part of the tail
    v1[0] = self.CREATE_VECTOR(-width, 0, 0)
    v1[1] = self.CREATE_VECTOR(-width, height, 0)
    v1[2] = self.CREATE_VECTOR(width, height, 0)
    v1[3] = self.CREATE_VECTOR(width, 0, 0)
    
    v2[0] = self.CREATE_VECTOR(-width, 0, 0)
    v2[1] = self.CREATE_VECTOR(-width, 0, self.tail2Size)
    v2[2] = self.CREATE_VECTOR(width, 0, self.tail2Size)
    v2[3] = self.CREATE_VECTOR(width, 0, 0)

    self.SMixBezier2(v1, 3, v2, 3)    
    

  def CREATE_VECTOR(self, x, y, z):
    C = [0 for i in range(4)]
    C[0]=x
    C[1]=y
    C[2]=z
    C[3]=1
    return C

  def Bern(self, s, j, n):
    return (self.fac(n)/(self.fac(n-j)*self.fac(j)))*pow(1-s, n-j)*pow(s,j)

  def fac(self, n):
    resul = 1  
    if n == 0:
      resul = 1
    else :
      resul = self.fac(n-1) * n     
    return  resul

  def PtBezier(self, s, p, np):
    V = self.CREATE_VECTOR(0, 0, 0)
    k = 0
    while k <= np:
      V = self.addV(V, self.mulV(self.Bern(s, k, np), p[k]))
      k += 1 
    return V

  def SMixBezier1(self, p, m1):
    N = self.tailRoundness   
    self.pp1 = [0 for i in range((N+1)*2)]
    a = 0.0
    b = 1.0
    c = 0.0
    d = 1.0

    ## Vectors for the first part of the tail (Incomplete, more vectors will be added
    ## when the size of the tail is known)
    j = 0
    i = 0
    v = c + (d - c) * j / N
    k = 0
    while k <= N:
      u1 = a+((b-a)*k)/N
      u2 = c+((d-c)*k)/N
      self.pp1[i] = self.mulV((1-v), self.PtBezier(u1, p, m1)) 
      k += 1
      i += 1

  def SMixBezier2(self, p, m1, q, m2):
    N = self.tailRoundness  
    vv = [0 for i in range((N+1)*(N+1))]
    a = 0.0
    b = 1.0
    c = 0.0
    d = 1.0

    ## Vectors for the second part of the tail (Complete, but unorganized)
    ## CURVE ON EACH HORIZONTAL********************
    j = 0
    i = 0
    while j <= N:
      v = c + (d - c) * j / N
      k = 0
      while k <= N:
        u1 = a+((b-a)*k)/N
        u2 = c+((d-c)*k)/N
        vv[i] = self.addV(self.mulV((1-v), self.PtBezier(u1, p, m1)), self.mulV(v, self.PtBezier(u2, q, m2))) 
        k += 1
        i += 1
      j += 1

    dd = (N+1)*(N+1) + N*(N-1)
    start = [0 for i in range(N+1)]
    i = 0
    while i <= N:
      start[i] = i*(N+1)
      i += 1
    self.pp2 = [0 for i in range(dd)]

    ## Rearrange vectors so that they form triangles and can be drawn
    i = 0
    k = 0
    mm = 0
    lim = 0
    while mm <= N-1:
      if lim == 0:
        lim = N
        var1 = k
        var2 = lim
        adj = -2
        inc = 1
      else:
        lim = 0
        var1 = lim
        var2 = k
        adj = 2
        inc = -1
      while var1 <= var2:
        self.pp2[i] = vv[start[k] + mm]
        self.pp2[i+1] = vv[start[k] + mm + 1]
        if var1 == var2 and (i+2) != dd:
          self.pp2[i+2] = vv[start[k] + mm + 2]
        k += inc
        i += 2
        if lim == N:
          var1 = k
        else:
          var2 = k
      i += 1
      k += adj
      mm += 1


  def addV(self, c, v):
    return self.CREATE_VECTOR(c[0]+v[0], c[1]+v[1], c[2]+v[2])


  def  mulV(self, s, u):
    C = [0 for i in range(4)]
    C[0] = s * u[0]
    C[1] = s * u[1]
    C[2] = s * u[2]
    C[3] = 1
    return  C


  def Poligon1(self, size, colortail):
    if size < 0:
        return
    
    V = self.CREATE_VECTOR(0, 0, size)
    N = len(self.pp1) / 2 - 1

    ## Complete the vectors for the first part of the tail, unorganized
    i = 0
    while i <= N:
      self.pp1[i+N+1] = self.addV(V, self.pp1[i]) 
      i += 1

    dd = ((N+1)*2) + (N-1)
    start = [0 for i in range(2)]
    i = 0
    while i <= 1:
      start[i] = i*(N+1)
      i += 1
    vv = [0 for i in range(dd)]

    ## Rearrange the vectors so that they form triangles and can be drawn
    i = 0
    k = 0
    mm = 0
    lim = 0
    while mm <= N-1:
      if lim == 0:
        lim = 1
        var1 = k
        var2 = lim
        adj = -2
        inc = 1
      else:
        lim = 0
        var1 = lim
        var2 = k
        adj = 2
        inc = -1
      while var1 <= var2:
        vv[i] = self.pp1[start[k] + mm]
        vv[i+1] = self.pp1[start[k] + mm + 1]
        if var1 == var2 and (i+2) != dd:
          vv[i+2] = self.pp1[start[k] + mm + 2]
        k += inc
        i += 2
        if lim == 1:
          var1 = k
        else:
          var2 = k
      i += 1
      k += adj
      mm += 1    

    ## Draw the first part of the tail
    j = 0
    glBegin(GL_TRIANGLE_STRIP)
    while j <= (dd - 1):
      u = vv[j]
      if u[0] > (self.tailWidth*2.0/3.0):
        glColor4f(0.7*colortail[0], 0.7*colortail[1], 0.7*colortail[2], colortail[3])
      elif u[0] < (-self.tailWidth*2.0/3.0):
        glColor4f(*colortail)
      else:
        glColor4f(1.5*colortail[0], 1.5*colortail[1], 1.5*colortail[2], colortail[3])
      glVertex3f(u[0], u[1], u[2])
      j += 1
    glEnd()


  def Poligon2(self, size, colortail):
    V = self.CREATE_VECTOR(0, 0, size)
    vv = [0 for i in range(len(self.pp2))]

    ## Move all the vectors in the z axis to their corresponding location
    i = 0
    while i <= len(self.pp2)-1:
      vv[i] = self.addV(V, self.pp2[i])
      i += 1

    ## Draw the second part of the tail
    j = 0
    glBegin(GL_TRIANGLE_STRIP)
    while j <= len(vv)-1:
      u = vv[j]
      if u[0] > (self.tailWidth*2.0/3.0):
        glColor4f(0.7*colortail[0], 0.7*colortail[1], 0.7*colortail[2], colortail[3])
      elif u[0] < (-self.tailWidth*2.0/3.0):
        glColor4f(*colortail)
      else:
        glColor4f(1.5*colortail[0], 1.5*colortail[1], 1.5*colortail[2], colortail[3])
      if u[2] < 0:
        glColor4f(0.0, 0.0, 0.0, 0.0)
      glVertex3f(u[0], u[1], u[2])
      j += 1
    glEnd()

      
  def renderNeck(self, visibility, song, pos):
    if not song:
      return
    
    v = visibility
    w = self.boardWidth
    l = self.boardLength
    offset = pos / self.fakePeriod
    beatsPerUnit = self.beatsPerBoard / self.boardLength
    glEnable(GL_TEXTURE_2D)
    self.neckDrawing.texture.bind()
    
    glBegin(GL_TRIANGLE_STRIP)
    glColor4f(1, 1, 1, 0)
    glTexCoord2f(0.0, (offset - 2 * beatsPerUnit) / 2)
    glVertex3f(-w / 2, 0, -2)
    glTexCoord2f(1.0, (offset - 2 * beatsPerUnit) / 2)
    glVertex3f( w / 2, 0, -2)
    
    glColor4f(1, 1, 1, v)
    glTexCoord2f(0.0, (offset - 1 * beatsPerUnit) / 2)
    glVertex3f(-w / 2, 0, -1)
    glTexCoord2f(1.0, (offset - 1 * beatsPerUnit) / 2)
    glVertex3f( w / 2, 0, -1)
    
    glTexCoord2f(0.0, (offset + l * beatsPerUnit * .7) / 2)
    glVertex3f(-w / 2, 0, l * .7)
    glTexCoord2f(1.0, (offset + l * beatsPerUnit * .7) / 2)
    glVertex3f( w / 2, 0, l * .7)
    
    glColor4f(1, 1, 1, 0)
    glTexCoord2f(0.0, (offset + l * beatsPerUnit) / 2)
    glVertex3f(-w / 2, 0, l)
    glTexCoord2f(1.0, (offset + l * beatsPerUnit) / 2)
    glVertex3f( w / 2, 0, l)
    glEnd()
    
    glDisable(GL_TEXTURE_2D)
    
  def renderTracks(self, visibility):
    w = self.boardWidth / self.strings
    v = 1.0 - visibility

    if self.editorMode:
      x = (self.strings / 2 - self.selectedString) * w
      s = 2 * w / self.strings
      z1 = -0.5 * visibility ** 2
      z2 = (self.boardLength - 0.5) * visibility ** 2
      
      glColor4f(1, 1, 1, .15)
      
      glBegin(GL_TRIANGLE_STRIP)
      glVertex3f(x - s, 0, z1)
      glVertex3f(x + s, 0, z1)
      glVertex3f(x - s, 0, z2)
      glVertex3f(x + s, 0, z2)
      glEnd()

    sw = 0.01
    c = 0.0
    c2 = 1
    if self.TracksType == 1:
      c = 0.4
      c2 = 2
    for n in range(self.strings - c2, -1, -1):
      glBegin(GL_TRIANGLE_STRIP)
      glColor4f(*(self.TracksColor + (0,)))
      glVertex3f(c + (n - self.strings / 2) * w - sw, -v, -2)
      glVertex3f(c + (n - self.strings / 2) * w + sw, -v, -2)
      glColor4f(*(self.TracksColor + (visibility * .75,)))
      glVertex3f(c + (n - self.strings / 2) * w - sw, -v, -1)
      glVertex3f(c + (n - self.strings / 2) * w + sw, -v, -1)
      glColor4f(*(self.TracksColor + (visibility * .75,)))
      glVertex3f(c + (n - self.strings / 2) * w - sw, -v, self.boardLength * .7)
      glVertex3f(c + (n - self.strings / 2) * w + sw, -v, self.boardLength * .7)
      glColor4f(*(self.TracksColor + (0,)))
      glVertex3f(c + (n - self.strings / 2) * w - sw, -v, self.boardLength)
      glVertex3f(c + (n - self.strings / 2) * w + sw, -v, self.boardLength)
      glEnd()
      v *= 2
      
      
  def renderBars2(self, visibility, song, pos):
    if not song:
      return
    
    w = self.boardWidth
    v = 1.0 - visibility
    sw = 0.02
    beatsPerUnit = self.beatsPerBoard / self.boardLength
    offset = pos / self.fakePeriod * beatsPerUnit
    
    currentBeat = pos / self.fakePeriod
    beat = int(currentBeat)

    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    
    glPushMatrix()
    while beat < currentBeat + self.beatsPerBoard:
      z = (beat - currentBeat) / beatsPerUnit

      if z > self.boardLength * .8:
        c = (self.boardLength - z) / (self.boardLength * .2)
      elif z < 0:
        c = max(0, 1 + z)
      else:
        c = 1.0
        
      glRotate(v * 90, 0, 0, 1)

      if (beat % 1.0) < 0.001:
        glColor4f(*(self.BarsColor + (visibility * c * .75,)))
      else:
        glColor4f(*(self.BarsColor + (visibility * c * .5,)))

      glBegin(GL_TRIANGLE_STRIP)
      glVertex3f(-(w / 2), -v, z + sw)
      glVertex3f(-(w / 2), -v, z - sw)
      glVertex3f(w / 2,    -v, z + sw)
      glVertex3f(w / 2,    -v, z - sw)
      glEnd()
      
      if self.editorMode:
        beat += 1.0 / 4.0
      else:
        beat += 1 
    glPopMatrix()

    Theme.setSelectedColor(visibility * .5)
    glBegin(GL_TRIANGLE_STRIP)
    glVertex3f(-w / 2, 0,  sw)
    glVertex3f(-w / 2, 0, -sw)
    glVertex3f(w / 2,  0,  sw)
    glVertex3f(w / 2,  0, -sw)
    glEnd()


  def renderBars(self, visibility, song, pos):
    if not song:
      return

    #Distance between bars
    beatsPerUnit = (5.0 * ( self.currentBpm/(self.fakeBpm/2.0))) / self.boardLength
    currentBeat = pos / (60000.0/self.currentBpm)
    beat = int(currentBeat)
    self.barDistance = ((beat+1 - currentBeat) / beatsPerUnit) - ((beat - currentBeat) / beatsPerUnit)
    if self.hyperS:
      self.barDistance = self.barDistance * 1.5

    #Speed of the bars
    currentBeat = pos / self.fakePeriod
    beat = int(currentBeat)
    self.zB = (beat - currentBeat) / (self.beatsPerBoard / self.boardLength)
    
    if self.zB < self.zBa:
      self.zBArray.append( abs(self.zB - self.zBa) )
      self.barSpeed = - abs(self.zB - self.zBa)
    else:
      add = 0.0
      if len(self.zBArray) == 0:
        cont = 1.0
      else:
        cont = len(self.zBArray)
      while len(self.zBArray) > 0:
        add += self.zBArray[0]
        self.zBArray.pop(0)
      prom = add / cont
      self.barSpeed = - prom

    self.zBa = self.zB

    w = self.boardWidth
    v = 1.0 - visibility
    sw = 0.02

    
    z = self.Za  + self.barSpeed

    if z < -3:
      z = self.Z2a + self.barSpeed

    self.Za = z
    self.Z2a = z + self.barDistance

    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

    glPushMatrix()
    while z < self.boardLength:      
      if z > self.boardLength * .8:
        c = (self.boardLength - z) / (self.boardLength * .2)
      elif z < 0:
        c = max(0, 1 + z)
      else:
        c = 1.0
        
      glRotate(v * 90, 0, 0, 1)

      glColor4f(*(self.BarsColor + (visibility * c * .5,)))

      glBegin(GL_TRIANGLE_STRIP)
      glVertex3f(-(w / 2), -v, z + sw)
      glVertex3f(-(w / 2), -v, z - sw)
      glVertex3f(w / 2,    -v, z + sw)
      glVertex3f(w / 2,    -v, z - sw)
      glEnd()      

      z = z + self.barDistance 
    glPopMatrix()

    Theme.setSelectedColor(visibility * .5)
    glBegin(GL_TRIANGLE_STRIP)
    glVertex3f(-w / 2, 0,  sw)
    glVertex3f(-w / 2, 0, -sw)
    glVertex3f(w / 2,  0,  sw)
    glVertex3f(w / 2,  0, -sw)
    glEnd()


  def renderNote(self, visibility, f, length, sustain, color, colortail, tailOnly = False, playedstart = False, playedcontinue = False, hopo = 0):   
    if self.jurgenStarted:
        mesh = self.jurgenNoteMesh
    else:
        mesh = self.noteMesh
    if not mesh:
      return

    if playedstart == False:
      p = 1
    elif playedstart == True and playedcontinue == False:
      p = 1
      colortail = (.2 + .4, .2 + .4, .2 + .4, .5 * visibility * f)
    else:
      p = 3   

    glColor4f(*colortail)
    

    if sustain:
      if playedstart == False or (playedstart == True and playedcontinue == False):
        size = (.075, length + 0.00001)
      else:
        size = (.125, length + 0.00001)

      ## Draw the first part of the tail
      self.Poligon1(size[1] - self.tail2Size, colortail)

      ## Draw the second part of the tail
      self.Poligon2(size[1] - self.tail2Size, colortail)      


    if tailOnly:
      return

    glColor4f(*color)
    
    glPushMatrix()
    glEnable(GL_DEPTH_TEST)
    glDepthMask(1)
    glShadeModel(GL_SMOOTH)
    glRotatef(90, 0, 1, 0)
    glRotatef(-90, 1, 0, 0)
    glColor3f(.75 * p * color[0], .75 * p * color[1], .75 * p * color[2])
    mesh.render("Mesh")
    if hopo > 1:
      glColor3f(self.hopoColor[0], self.hopoColor[1], self.hopoColor[2])
      mesh.render("Mesh_001")
      glColor3f(self.hopoColor2[0], self.hopoColor2[1], self.hopoColor2[2])
      mesh.render("Mesh_002")
    else:
      glColor3f(1, 1, 1)
      mesh.render("Mesh_001")
      glColor3f(0.25 * p * color[0], 0.25 * p * color[1], 0.25 * p * color[2])
      mesh.render("Mesh_002")
    glDepthMask(0)
    glPopMatrix()

  def renderNotes(self, visibility, song, pos):
    if not song:
      return

    # Scale the board according to the current tempo
    if not self.editorMode:
      if self.boardSpeed == 0 or self.boardSpeed == 1:
        self.beatsPerBoard = 5.0 * (self.fakeBpm / self.fakeCurrentBpm)
      elif self.boardSpeed == 2:
        self.beatsPerBoard = 5.0 * (self.fakeBpm / self.currentBpm)

    beatsPerUnit = self.beatsPerBoard / self.boardLength
    w = self.boardWidth / self.strings
    track = song.track[self.player]
    
    
    #Maybe make this more efficient
    for time, event in track.getEvents(pos - self.fakePeriod * 2, pos + self.fakePeriod * self.beatsPerBoard):
      if isinstance(event, Tempo):
        self.targetBpm = event.bpm
        continue
      
      if not isinstance(event, Note):
        continue
      if self.jurgenStarted and self.jPowerNotes:
        c = self.fretColors[6]
      else:  
        c = self.fretColors[event.number]
      

      x  = (self.strings / 2 - event.number) * w
      z  = ((time - pos) / self.fakePeriod) / beatsPerUnit
      z2 = ((time + event.length - pos) / self.fakePeriod) / beatsPerUnit
      
      if z > self.boardLength * .8:
        f = (self.boardLength - z) / (self.boardLength * .2)
      elif z < 0:
        f = min(1, max(0, 1 + z2))
      else:
        f = 1.0

      color      = (.1 + .8 * c[0], .1 + .8 * c[1], .1 + .8 * c[2], 1 * visibility * f)
      colortail  = color
      length     = event.length / self.fakePeriod / beatsPerUnit
      tailOnly   = False
      hopo = event.hopo
      playedstart = False
      playedcontinue = False
      

     # Clip the played notes to the origin
      if event.played or event.hopod:
        playedstart = True
        tailOnly = True
        length += z
        z = 0
        if length <= 0:
          continue
      if z < 0 and not (event.played or event.hopod):   
        colortail = (.2 + .4, .2 + .4, .2 + .4, .5 * visibility * f)

      sustain = False
      if event.length >= 281.0:
        sustain = True
        
      e = event.number
      if playedstart == True:
        for time, event in self.playedNotes:
          if e == event.number:
            playedcontinue = True        

      glPushMatrix()
      glTranslatef(x, (1.0 - visibility) ** (e + 1), z)
      self.renderNote(visibility, f, length, sustain = sustain, color = color, colortail = colortail, tailOnly = tailOnly, playedstart = playedstart, playedcontinue = playedcontinue, hopo = hopo)
      glPopMatrix()


    if self.disableNoteSFX == True:
      return
    
    glBlendFunc(GL_ONE, GL_ONE)
    for time, event in self.playedNotes:
      c = self.fretColors[event.number]
      x = (self.strings / 2 - event.number) * w
      z = ((time - pos) / self.fakePeriod) / beatsPerUnit
      length     = event.length / self.fakePeriod / beatsPerUnit
      tailOnly   = False

      if event.played or event.hopod:
        tailOnly = True
        length += z
        z = 0
        if length <= 0:
          continue

      sustain = False
      if event.length >= 281.0:
        sustain = True
      
      glPushMatrix()
      glTranslatef(x, 0, z)
      for x in range(10):
        glScalef(1.05, 1, 1)
        glTranslatef(0, .005, 0)
        f = 1.0 - (x / 10.0)
        color = (f * c[0], f * c[1], f * c[2], 1)
        self.renderNote(visibility, f, length, sustain, color = color, colortail = color, tailOnly = tailOnly)
      glPopMatrix()
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        

  def renderFrets(self, visibility, song, controls):
    w = self.boardWidth / self.strings
    size = (.22, .22)
    v = 1.0 - visibility
    
    glEnable(GL_DEPTH_TEST)
    
    for n in range(self.strings):
      f = self.fretWeight[n]
      c = self.fretColors[n]

      if f and (controls.getState(self.actions[0]) or controls.getState(self.actions[1])):
        f += 0.25

      y = v + f / 6
      x = (self.strings / 2 - n) * w

      if self.keyMesh:
        glPushMatrix()
        glTranslatef(x, y + v * 6, 0)
        glDepthMask(1)
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        glShadeModel(GL_SMOOTH)
        glRotatef(90, 0, 1, 0)
        glLightfv(GL_LIGHT0, GL_POSITION, (5.0, 10.0, -10.0, 0.0))
        glLightfv(GL_LIGHT0, GL_AMBIENT,  (.2, .2, .2, 0.0))
        glLightfv(GL_LIGHT0, GL_DIFFUSE,  (1.0, 1.0, 1.0, 0.0))
        glRotatef(-90, 1, 0, 0)
        glRotatef(-90, 0, 0, 1)
        glColor4f(.1 + .8 * c[0] + f, .1 + .8 * c[1] + f, .1 + .8 * c[2] + f, visibility)
        self.keyMesh.render("Mesh")
        glColor3f(self.keyColor[0], self.keyColor[1], self.keyColor[2])
        self.keyMesh.render("Mesh_001")
        glColor3f(self.key2Color[0], self.key2Color[1], self.key2Color[2])
        self.keyMesh.render("Mesh_002")
        glDisable(GL_LIGHTING)
        glDisable(GL_LIGHT0)
        glDepthMask(0)
        glPopMatrix()

      f = self.fretActivity[n]

      if f and self.disableFretSFX != True:
        glBlendFunc(GL_ONE, GL_ONE)

        s = 0.0
        while s < 1:
          ms = s * (math.sin(self.time) * .25 + 1)
          glColor3f(c[0] * (1 - ms), c[1] * (1 - ms), c[2] * (1 - ms))
          glPushMatrix()
          glTranslate(x, y, 0)
          glScalef(1 + .6 * ms * f, 1 + .6 * ms * f, 1 + .6 * ms * f)
          glRotatef( 90, 0, 1, 0)
          glRotatef(-90, 1, 0, 0)
          glRotatef(-90, 0, 0, 1)
          glColor3f(.50 * c[0] * (1 - ms), .50 * c[1] * (1 - ms), .50 * c[2] * (1 - ms))
          self.keyMesh.render("Mesh_003")
          glPopMatrix()
          s += 0.2

        glColor3f(c[0], c[1], c[2])
        glEnable(GL_TEXTURE_2D)
        self.glowDrawing.texture.bind()
        f += 2

        glPushMatrix()
        glTranslate(x, y, 0)
        glRotate(f * 90 + self.time, 0, 1, 0)
        glBegin(GL_TRIANGLE_STRIP)
        glTexCoord2f(0.0, 0.0)
        glVertex3f(-size[0] * f, 0, -size[1] * f)
        glTexCoord2f(1.0, 0.0)
        glVertex3f( size[0] * f, 0, -size[1] * f)
        glTexCoord2f(0.0, 1.0)
        glVertex3f(-size[0] * f, 0,  size[1] * f)
        glTexCoord2f(1.0, 1.0)
        glVertex3f( size[0] * f, 0,  size[1] * f)
        glEnd()
        glPopMatrix()
        
        glDisable(GL_TEXTURE_2D)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)       

      v *= 1.5
    glDisable(GL_DEPTH_TEST)


  def renderFlames(self, visibility, song, pos, controls):
    if not song:
      return

    beatsPerUnit = self.beatsPerBoard / self.boardLength
    w = self.boardWidth / self.strings
    track = song.track[self.player]

    size = (.22, .22)
    v = 1.0 - visibility

    if self.disableFlame1SFX != True:
      for n in range(self.strings):
        f = self.fretWeight[n]
        c = self.fretColors[n]
        if f and (controls.getState(self.actions[0]) or controls.getState(self.actions[1])):
          f += 0.25      
        y = v + f / 6
        x = (self.strings / 2 - n) * w
        f = self.fretActivity[n]

        if f:
          ms = math.sin(self.time) * .25 + 1
          ff = f
          ff += 1.2
          
          glBlendFunc(GL_ONE, GL_ONE)
          
          firesize = (.075, .075)
          firecolor = self.fireColor[n][self.ScoreMultiplier - 1]
          firecolor = (firecolor[0] * 1.1973333333333333333333333333333, firecolor[1] * 1.9710526315789473684210526315789, firecolor[2] * 10.592592592592592592592592592593)
          
          glColor3f(firecolor[0], firecolor[1], firecolor[2])
          glEnable(GL_TEXTURE_2D)
          self.hitglowDrawing.texture.bind()    
          glPushMatrix()
          glTranslate(x, y +.125, 0)
          glRotate(90, 1, 0, 0)
          glScalef(0.5 + .6 * ms * ff, 1.5 + .6 * ms * ff, 1 + .6 * ms * ff)
          glBegin(GL_TRIANGLE_STRIP)
          glTexCoord2f(0.0, 0.0)
          glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
          glTexCoord2f(1.0, 0.0)
          glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
          glTexCoord2f(0.0, 1.0)
          glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
          glTexCoord2f(1.0, 1.0)
          glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
          glEnd()
          glPopMatrix()
          glDisable(GL_TEXTURE_2D)

          ff += .3
          firesize = (.075, .075)
          firecolor = self.fireColor[n][self.ScoreMultiplier - 1]
          firecolor = (firecolor[0] * 1.1973333333333333333333333333333, firecolor[1] * 1.7842105263157894736842105263158, firecolor[2] * 12.222222222222222222222222222222)
          
          glColor3f(firecolor[0], firecolor[1], firecolor[2])
          glEnable(GL_TEXTURE_2D)
          self.hitglow2Drawing.texture.bind()    
          glPushMatrix()
          glTranslate(x, y + .25, .05)
          glRotate(90, 1, 0, 0)
          glScalef(.40 + .6 * ms * ff, 1.5 + .6 * ms * ff, 1 + .6 * ms * ff)
          glBegin(GL_TRIANGLE_STRIP)
          glTexCoord2f(0.0, 0.0)
          glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
          glTexCoord2f(1.0, 0.0)
          glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
          glTexCoord2f(0.0, 1.0)
          glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
          glTexCoord2f(1.0, 1.0)
          glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
          glEnd()
          glPopMatrix()
          glDisable(GL_TEXTURE_2D)
          
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)


    if self.disableFlame2SFX != True:
      firelimit = 10.0
      halffirelimit = round(firelimit/2.0)
      for time, event in track.getEvents(pos - self.fakePeriod * 2, pos + self.fakePeriod * self.beatsPerBoard):
        if isinstance(event, Tempo):
          continue
        
        if not isinstance(event, Note):
          continue
        
        if (event.played or event.hopod) and event.firecount < firelimit:
          ms = math.sin(self.time) * .25 + 1
          if event.number == 5:
            x  = (self.strings / 2 - 2) * w
          else:
            x  = (self.strings / 2 - event.number) * w
          ff = 1 + 0.25       
          y = v + ff / 6
          glBlendFunc(GL_ONE, GL_ONE)
          
          firesize = self.fireSize[event.number][self.ScoreMultiplier - 1]
          firecolor = self.fireColor[event.number][self.ScoreMultiplier - 1]
          ff += 1.5

          if event.firecount < halffirelimit:
            glColor3f(firecolor[0], firecolor[1], firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames2Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x, y + .20, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.25 + .6 * ms * ff, event.firecount/6.0 + .6 * ms * ff, event.firecount/6.0 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()
            glDisable(GL_TEXTURE_2D) 

            glColor3f(firecolor[0], firecolor[1], firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames2Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x-.005, y +.25 +.005, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.30 + .6 * ms * ff, (event.firecount+1)/5.5 + .6 * ms * ff, (event.firecount+1)/5.5 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()	  
            glDisable(GL_TEXTURE_2D)

            glColor3f(firecolor[0], firecolor[1], firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames2Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x+.005, y +.25 +.005, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.35 + .6 * ms * ff, (event.firecount+1)/5.0 + .6 * ms * ff, (event.firecount+1)/5.0 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()	  
            glDisable(GL_TEXTURE_2D)

            glColor3f(firecolor[0], firecolor[1], firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames2Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x, y +.25 +.005, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.40 + .6 * ms * ff, (event.firecount+1)/4.7 + .6 * ms * ff, (event.firecount+1)/4.7 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()	  
            glDisable(GL_TEXTURE_2D)
          else:
            glColor3f(0.1*(firelimit-event.firecount)* firecolor[0], 0.1*(firelimit-event.firecount)* firecolor[1], 0.1*(firelimit-event.firecount)* firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames1Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x, y +.35, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.25 + .6 * ms * ff, event.firecount/3.0 + .6 * ms * ff, event.firecount/3.0 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()
            glDisable(GL_TEXTURE_2D)

            glColor3f(0.1*(firelimit-event.firecount)* firecolor[0], 0.1*(firelimit-event.firecount)* firecolor[1], 0.1*(firelimit-event.firecount)* firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames1Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x-.005, y +.40 +.005, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.30 + .6 * ms * ff, (event.firecount+1)/2.5 + .6 * ms * ff, (event.firecount+1)/2.5 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()  
            glDisable(GL_TEXTURE_2D)

            glColor3f(0.1*(firelimit-event.firecount)* firecolor[0], 0.1*(firelimit-event.firecount)* firecolor[1], 0.1*(firelimit-event.firecount)* firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames1Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x+.005, y +.35 +.005, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.35 + .6 * ms * ff, (event.firecount+1)/2.0 + .6 * ms * ff, (event.firecount+1)/2.0 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()  
            glDisable(GL_TEXTURE_2D)

            glColor3f(0.1*(firelimit-event.firecount)* firecolor[0], 0.1*(firelimit-event.firecount)* firecolor[1], 0.1*(firelimit-event.firecount)* firecolor[2])
            glEnable(GL_TEXTURE_2D)
            self.hitflames1Drawing.texture.bind()    
            glPushMatrix()
            glTranslate(x+.005, y +.35 +.005, 0)
            glRotate(90, 1, 0, 0)
            glScalef(.40 + .6 * ms * ff, (event.firecount+1)/1.7 + .6 * ms * ff, (event.firecount+1)/1.7 + .6 * ms * ff)
            glBegin(GL_TRIANGLE_STRIP)
            glTexCoord2f(0.0, 0.0)
            glVertex3f(-firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(1.0, 0.0)
            glVertex3f( firesize[0] * ff, 0, -firesize[1] * ff)
            glTexCoord2f(0.0, 1.0)
            glVertex3f(-firesize[0] * ff, 0,  firesize[1] * ff)
            glTexCoord2f(1.0, 1.0)
            glVertex3f( firesize[0] * ff, 0,  firesize[1] * ff)
            glEnd()
            glPopMatrix()  
            glDisable(GL_TEXTURE_2D)
         
          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
          event.firecount += 1
        

  def render(self, visibility, song, pos, controls):
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    glEnable(GL_COLOR_MATERIAL)
    if self.leftyMode:
      glScale(-1, 1, 1)

    self.renderNeck(visibility, song, pos)
    if str(self.TracksColor) != "off":
      self.renderTracks(visibility)
    if str(self.BarsColor) != "off":
      if self.boardSpeed == 0:
        self.renderBars(visibility, song, pos)
      else:
        self.renderBars2(visibility, song, pos)
    self.renderNotes(visibility, song, pos)
    self.renderFrets(visibility, song, controls)
    self.renderFlames(visibility, song, pos, controls)
    
    if self.leftyMode:
      glScale(-1, 1, 1)

  def getMissedNotes(self, song, pos, catchup = False):
    if not song:
      return

    m1      = self.lateMargin
    m2      = self.lateMargin * 2

    if catchup == True:
      m2 = 0
      
    track   = song.track[self.player]
    notes   = [(time, event) for time, event in track.getEvents(pos - m1, pos - m2) if isinstance(event, Note)]
    notes   = [(time, event) for time, event in notes if (time >= (pos - m2)) and (time <= (pos - m1))]
    notes   = [(time, event) for time, event in notes if not event.played and not event.hopod and not event.skipped and not event.missed]
    for time, event in notes:
        event.missed = True
    if catchup == True:
      for time, event in notes:
        event.skipped = True
    return notes
    
  def getRequiredNotes(self, song, pos, hopo = False):
    track = song.track[self.player]
    notes = [(time, event) for time, event in track.getEvents(pos - self.lateMargin, pos + self.earlyMargin) if isinstance(event, Note)]
    if hopo:
      notes = [(time, event) for time, event in notes if not (event.hopod or event.played)]
    else:
      notes = [(time, event) for time, event in notes if not (event.played)]
    notes = [(time, event) for time, event in notes if (time >= (pos - self.lateMargin)) and (time <= (pos + self.earlyMargin))]
    return notes
  
  
  def hitNote(self, time, note):
     self.pickStartPos = max(self.pickStartPos, time)
     self.playedNotes = [(time, note)]
     note.played       = True
     return True  
  
  
  def startPick(self, song, pos, controls, hopo = False):
    twochord = 0
    if not song:
      return
  
    notes = self.getRequiredNotes(song, pos, hopo)

    # no notes?
    if not notes:
      return False

    # check each valid chord
    chords = {}
    for time, note in notes:
      if note.hopod == True and controls.getState(self.keys[note.number]):
      #if hopo == True and controls.getState(self.keys[note.number]):
        self.playedNotes = []
        return True
      if not time in chords:
        chords[time] = []
      chords[time].append((time, note))

    self.playedNotes = []
    #Make sure the notes are in the right time order
    chordlist = chords.values()
    chordlist.sort(lambda a, b: cmp(a[0][0], b[0][0]))
    
    for notes in chordlist:
      # matching keys?
      requiredKeys = [note.number for time, note in notes]
     
      if len(requiredKeys) > 2 and self.twoChordMax == True:
        requiredKeys = [min(requiredKeys), max(requiredKeys)]
        twochord = 1

      for n, k in enumerate(self.keys):
        if n in requiredKeys and not controls.getState(k):
          break
        if not n in requiredKeys and controls.getState(k):
          # The lower frets can be held down
          if hopo == False and n >= min(requiredKeys):
            break
      else:
        self.pickStartPos = pos
        for time, note in notes:
          self.pickStartPos = max(self.pickStartPos, time)
          if hopo:
            note.hopod        = True
          else:
            note.played       = True
          if note.hopo == 1 or note.hopo == 2:
            self.hopoActive = time
          elif note.hopo == 3:
            self.hopoActive = -time
          else:
            self.hopoActive = 0
        self.hopoLast     = note.number
        self.playedNotes = notes
        if twochord == 1:
          self.twoChord += 1
        return True
    return False

  def endPick(self, pos):
    self.playedNotes = []
    for time, note in self.playedNotes:
      if time + note.length > pos + self.noteReleaseMargin:
        return False
    return True
    
  def getPickLength(self, pos):
    if not self.playedNotes:
      return 0.0
    
    # The pick length is limited by the played notes
    pickLength = pos - self.pickStartPos
    for time, note in self.playedNotes:
      pickLength = min(pickLength, note.length)
    return pickLength

  def run(self, ticks, pos, controls):
    self.time += ticks
    
    # update frets
    if self.editorMode:
      if (controls.getState(self.actions[0]) or controls.getState(self.actions[1])):
        activeFrets = [i for i, k in enumerate(self.keys) if controls.getState(k)] or [self.selectedString]
      else:
        activeFrets = []
    else:
      activeFrets = [note.number for time, note in self.playedNotes]

    
    for n in range(self.strings):
      if controls.getState(self.keys[n]) or (self.editorMode and self.selectedString == n):
        self.fretWeight[n] = 0.5
      else:
        self.fretWeight[n] = max(self.fretWeight[n] - ticks / 64.0, 0.0)
      if n in activeFrets:
        self.fretActivity[n] = min(self.fretActivity[n] + ticks / 32.0, 1.0)
      else:
        self.fretActivity[n] = max(self.fretActivity[n] - ticks / 64.0, 0.0)
      if 5 in activeFrets:
        self.fretActivity[n] = min(self.fretActivity[n] + ticks / 24.0, 0.6)

    for time, note in self.playedNotes:
      if pos > time + note.length:
        return False

    # update bpm
    diff = self.targetBpm - self.currentBpm
    self.currentBpm += diff * .01

    self.setMargin()

    return True
